//
// Created by liaohailong on 2025/4/11.
//

#include "HelloDataFetcher.hpp"

HelloDataFetcher::HelloDataFetcher(const std::shared_ptr<HelloCacheManager> &cache,
                                   const std::shared_ptr<HelloHttpRequest> &request,
                                   const std::shared_ptr<HelloRange> &range,
                                   const char *tag) :
        logger(tag), cache(cache), request(request), range(range), worker(nullptr), running(false),
        callbackCtx(nullptr), next(nullptr)
{
    logger.i("HelloDataFetcher::HelloDataFetcher(%p)", this);
}

HelloDataFetcher::~HelloDataFetcher()
{
    stop();
    logger.i("HelloDataFetcher::~HelloDataFetcher(%p)", this);
}


const std::shared_ptr<HelloHttpRequest> &HelloDataFetcher::getRequest() noexcept
{
    return request;
}

const std::shared_ptr<HelloRange> &HelloDataFetcher::getRange() noexcept
{
    return range;
}

void HelloDataFetcher::setNext(const std::shared_ptr<HelloDataFetcher> &fetcher)
{
    this->next = fetcher;
}

void HelloDataFetcher::setOnCompleteCallback(OnCompleteCallback callback, void *userdata)
{
    callbackCtx = std::make_shared<OnCompleteCallbackCtx>();
    callbackCtx->cb = callback;
    callbackCtx->userdata = userdata;
}

const std::shared_ptr<HelloCacheInfo> &HelloDataFetcher::getCacheInfo()
{
    const std::string &url = request->getRealUrl();
    return cache->getCacheInfo(url);
}

void HelloDataFetcher::start()
{
    if (worker)return;
    worker = new std::thread(&HelloDataFetcher::fetch, std::ref(*this));
}

void HelloDataFetcher::stop(bool join)
{
    running = false;

    // next对象是复用本线程
    if (next)
    {
        next->stop(join);
    }
    if (worker)
    {
        if (join && worker->joinable())
        {
            worker->join();
        }
        delete worker;
        worker = nullptr;
    }
}

void HelloDataFetcher::fetch()
{
    running = true;

    // 真正处理
    run(request);

    // 处理下一个,复用本线程处理
    if (next)
    {
        next->fetch();
    }

    // 运行完毕,回调一下
    if (callbackCtx && callbackCtx->cb && running)
    {
        callbackCtx->cb(this, callbackCtx->userdata);
    }
    running = false;
}

bool HelloDataFetcher::sendHeader()
{
    // 客户端连接句柄
    const int fd = request->getConnFd();
    const std::string &url = request->getRealUrl();

    // 判断标记位：是否需要写 header 给客户端，所有的 fetcher 都是共用一个 request
    if (request->needWriteHeader())
    {
        // 构建一个 HTTP response
        const std::shared_ptr<HelloCacheInfo> &cacheInfo = getCacheInfo();
        if (cacheInfo->available())
        {
            // 有缓存信息
            const std::string &contentType = cacheInfo->getContentType(); // video/mp4 ...等等

            // Header + Body
            const int64_t contentLength = cacheInfo->getContentLength();
            const std::string &header = getResponseHeader(range, contentLength, contentType);
            // 写回客户端：响应头header
            ssize_t n = send(fd, header.c_str(), header.size(), 0); // 量小，用send函数一次性就过去了
            logger.i("[CACHED]Response to client[%d] writen[%d]: \n%s", fd, n, header.c_str());

            // 更新标记位，已经写过 header 给客户端了，防止后续 fetcher 再写一次
            request->markHeaderWriten();
            return true;
        } else
        {
            // 本地没缓存，header信息构成不了
            return false;
        }
    }

    return true;
}

std::string HelloDataFetcher::getResponseHeader(const std::shared_ptr<HelloRange> &range,
                                                int64_t contentLength, const std::string &type)
{
    return HelloHeader::getResponseHeader(range, contentLength, type);
}
